In previous chapter, we learned numerical calculations in scalar operations.
In this chapter, we will consider how this concept extends to arrays. However, there are also complicated operations that requires the “operator”, I’ll explain those use-cases in next chapter.
Today, many of general-purpose programming languages handle arrays with the procedural method. However, this approach is incompatible with that of vector algebra. The APL-family languages including AROAPL have already solved this problem with the mathematical notation, and parallel calculation called SIMD. Therefore, it is very simple and easy to understand what the program wants to do for programmers read it and for computers execute it.
Though vector and matrix are the part of curriculum of mathematics for 12th graders and first-year undergraduate students, their fundamental principles and operations are very simple, so there is no need to worry.

3.1. Vector Array

It is not difficult to understand what “array” is.
Array is set of values as a variable. For example, in case of integer array:

ARR: ι[5] ← 5 ¯2 8 17 0;

At this point, we don’t use delimiters such as [ ], { }, or ( ) when defining an array. Even in case of high dimentional arrays, too. I’ll explain it later.

Also, please be careful not to define different typed values in an array:

⎕ ← 5 "A" ⊤ 5. 5.J5.; 
VALUE ERROR: ALL ELEMENTS MUST BE THE SAME TYPE

3.1.1. Sequence

In mathematical terms, array equals “sequence”. Therefore, a rearranged array is not considered to be the same as the original:

⎕ ← 5 ¯2 8 17 0 ≡ 0 ¯2 17 5 8;
⊥

By the way, if you calculate with not using ≡ (match) but using = (equal), each elements are compared:

⎕ ← 5 ¯2 8 17 0 = 0 ¯2 5 17 8;
⊥ ⊤ ⊥ ⊤ ⊥

3.1.2. Retrieving with an Index

In other words, since an array is a sequence of elements, you can specify an index to retrieve its value.
However, please be sure to keep in mind that the indices start at 0.

A ← 5 ¯2 8 17 0;
⎕ ← A[0];
⎕ ← A[1];
⎕ ← A[2];
⎕ ← A[3];
⎕ ← A[4];
5
¯2
8 
17 
0

If you define out of range of an array, it returns error:

A ← 5 ¯2 8 17 0;
⎕ ← A[5];
INDEX OUT OF RANGE ERROR: LENGTH OF ARRAY IS 5, BUT YOU INDEXED 5

And you may set negative index:

A ← 5 ¯2 8 17 0;
⎕ ← A[¯1];
⎕ ← A[¯2];
⎕ ← A[¯3];
⎕ ← A[¯4];
⎕ ← A[¯5];
0
17
8
¯2
5

Of course, about out of range:

A ← 5 ¯2 8 17 0;
⎕ ← A[¯6];
INDEX OUT OF RANGE ERROR: SIZE OF ARRAY IS 5, BUT YOU INDEXED ¯6

Additionally, it is one of interesting things in AROAPL, we can extract multi indexes as a new array:

A ← 5 ¯2 8 17 0;
⎕ ← A[0 ¯1 1 ¯2 2 4 ¯5 3 3];
5 0 ¯2 17 ¯2 0 5 17 17

3.1.3. Size of Array

To get size of array, ρ (get shape) monad function:

A ← 5 ¯2 8 17 0;
⎕ ← ρA;
5

3.1.4. Type Definition

When defining variables with type, we can declare the size of array as either fixed or dynamic:

A: ι[5] ← 5 ¯2 8 17 0; ⍝ FIXED ⍝
B: ι[?] ← 5 ¯2 8 17 0; ⍝ DYNAMIC ⍝

⎕ ← A;
⎕ ← B;
⎕ ← "";
⎕ ← ρA;
⎕ ← ρB;
5 ¯2 8 17 0
5 ¯2 8 17 0

5
5

In case of fixed, if size of array are different to specified size, it is error:

A: ι[4] ← 5 ¯2 8 17 0;
SIZE OF ARRAY ERROR: IT IS NOT AN ARRAY OF SPECIFIED LENGTH 5 → 4

And in case of dynamic, it must not be happened bacause size is decided after declaired array.

The reason dynamic type definition are also necessary is that they offer various benefits.
To begin with, there are cases that we cannot decide size until variable declaired. For example, string, contents of files, hit cases, and so on.

3.1.5. Array Generation

If you want to get ordered-indexes array, ι (index array generator) monad function is convinience:

⎕ ← ι4;
0 1 2 3

Moreover, if you want an shuffled-indexes array. ? (random index array generator) monad function is useful:

⎕ ← ?6;
4 1 0 2 3 5

3.1.6. Extending Monadic Functions to Array

If we extend a monadic function applied to scalar to array, each values are applied.

⎕ ← - ¯2. 3.43 8. ¯2.66
2. ¯3.43 ¯8. 2.66

But they are the exceptions: ι (ordered index array generator), ρ (shape extractor), = (hit cases), ⌹ (matrix inversion), ⍉ (matrix transposition), and monadic operators.
Except them, we extend others to that, too.

Also, high dimentional array works, too.

3.1.7. Extending Dyadic Functions to Array

There are two approaches to extending dyadic functions.

For dyadic operations between scalar and array, scalar applies to each values of array.

⎕ ← ¯6 + 4 1 0 2 3 5;
¯2 ¯5 ¯6 ¯4 ¯3 ¯1

For dyadic operations between array and array that both are the same size, both each values on the same index are operated.

⎕ ← 4 1 0 2 3 5 + ¯3 5 5 8 8 2;
1 6 5 10 11 7

If size of both arrays are different, we cannot operate.

⎕ ← ¯6 9 + 4 1 0 2 3 5;
DIFFERENT SIZED ARRAY CALCULATION: 6 2

However, only & (combination) method is the exception. I’ll introduct it next.

3.1.8. Combine

To combine both arrays, we use & (combination) dyad function.
It doesn’t matter if size of both arrays are different.

⎕ ← 4 8 2 & 9 8 5 3;
4 8 2 9 8 5 3

Also, to repeat, unfortunately, we cannot overwrite value of variable in AROAPL.
Therefore, it is not suitable to append sequentially or iteratively. In such cases, consider using parallel processing to apply in bulk.

3.1.9. Split

AROAPL doesn’t support split method. But, we can use extraction by indexes alternatively.

A ← 5 ¯2 8 17 0;
⎕ ← A[1 + ι3];
¯2 8 17

3.1.10. Hit Cases

There are some cases that we want to extract indexes of hit cases.
= (hit cases) monad function is convinience:

A ← 5 ¯2 8 17 0;
B ← 0 ¯2 5 17 8;
⎕ ← A = B;
⎕ ← = A = B;
⎕ ← A[= A = B];
⊥ ⊤ ⊥ ⊤ ⊥
1 3
¯2 17

3.2. High Dimentional Array as Tensor

Next, let’s learn how to define and operate high dimentional array.
There are many points we require special attentions.

High dimentional array in AROAPL is always tensor.
In vector, size of array is single element of count. In tensor, it becomes multiply. As another explanation, each element of tensor assigned with multiple indexes.
Therefore, all child arrays of parent high dimentional array must be of the same size. This principle is called regularity.

For example, this is regular:

 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

But this is not, and not allowed:

 8  9 4 3
 9  7
¯9 ¯8 7

Why does is do that? As the simplest of explanation, it is able to be expressed:

HA ← ι[3 4] ← ...

Also, for both of computers (memory accessor), and programmers, regulared alignment is the most readable. Actually, regulared high dimentional array can be accessed super faster than not. I’ll explain it in chapter 13.
And surely, we’ve understood irregular high dimentional array is also essential to define and operate. We have method to express by using tuple structure at chapter 7.

For more details, I’ll divide as sub-sections.

3.2.1. Defining with Reshape

There are two ways how to declair high dimentional array.

  1. reshape vector
  2. load CSV or DCF

I’ll explain the latter method in chapter 6.

We use ρ (reshape) dyad function.

In case of matrix,

⎕ ← 2 3 ρ 2 ¯5 8 9 2 4;
2 ¯5 8
9  2 4

In case of three dimentional array:

⎕ ← 3 2 3 ρ 1 ¯5 8 9 2 4 2 ¯5 8 9 2 4 3 ¯5 8 9 2 4;
1 ¯5 8
9  2 4

2 ¯5 8
9  2 4

3 ¯5 8
9  2 4

Of course, we can get shape.

A ← 2 3 ρ 2 ¯5 8 9 2 4;
⎕ ← ρA;
B ← 3 2 3 ρ 1 ¯5 8 9 2 4 2 ¯5 8 9 2 4 3 ¯5 8 9 2 4;
⎕ ← ρB;
2 3
3 2 3

It occurs error if we define different size:

⎕ ← 2 3 ρ 2 ¯5 8 9 2;
SIZE OF ARRAY ERROR: ARRAY IS NOT RESHAPABLE 2 3 ρ 5

3.2.2. Extracting Sub Elements with Indexes

Extracting sub elements in high dimentional array has multiple methods.

Getting single value:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← A[1, 2];
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

¯5

We need , delimiter between indexes. This is for getting sub array:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
B ← A[0 2, 2];
C ← A[1, 0 2 3];
D ← A[0 2, 0 2 3];

⎕ ← A;
⎕ ← "";
⎕ ← B;
⎕ ← "";
⎕ ← ρB;
⎕ ← "";
⎕ ← C;
⎕ ← "";
⎕ ← ρC;
⎕ ← "";
⎕ ← D;
⎕ ← "";
⎕ ← ρD;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

4
7

2 1

9 ¯5 3

3

 8 4 3
¯9 7 6

2 3

3.2.3. Extending Monadic Functions to High Dimentional Array

Basic monad functions are simple:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← -A;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

¯8 ¯9 ¯4 ¯3
¯9 ¯7  5 ¯3
 9  8 ¯7 ¯6

But = (hit cases) monad function is a littele bit special:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← 4 ≥ A;
⎕ ← "";
⎕ ← = 4 ≥ A;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

⊤ ⊤ ⊤ ⊥
⊤ ⊤ ⊥ ⊥
⊥ ⊥ ⊤ ⊤

0 0
0 1
0 2
1 0
1 1
2 2
2 3

In this case, how to get sub elements by using extracted indexes by hit cases?
Actually, we don’t have effective methods yet to solve it. We’ll learn in the next chapter.

3.2.4. Extending Dyadic Functions to High Dimentional Array

Between scalar and matrix:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← ¯4 + A;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

  4   5  0 ¯1
  5   3 ¯9 ¯1
¯13 ¯12  3  2

Between vector and matrix:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← ¯4 3 8 5 + A;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

  4  12 12  8
  5  10  3  8
¯13 ¯5  15 11

And, between matrix and matrix:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
B ← 3 4 ρ ¯4 3 8 5 ¯8 9 7 0 0 ¯16 ¯23 ¯36;
⎕ ← A;
⎕ ← "";
⎕ ← B;
⎕ ← "";
⎕ ← A + B;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

¯4   3   8   5
¯8   9   7   0
 0 ¯16 ¯23 ¯36

 4  12  12   8
 1  16   2   3
¯9 ¯24 ¯16 ¯30

3.2.5. Matrix Inversion

This is a special function. There are only two: ⌹ (matrix inversion) and ⍉ (matrix transposition).
⌹ (matrix inversion) monad function is simple. Just culculate the inverse matrix:

A ← 2 2 ρ 2. ¯3. 4. 10.;
⎕ ← A;
⎕ ← "";
⎕ ← ⌹A;
2 . ¯3.
4.  10.

 0.3125 0.09375
¯0.125  0.0625

3.2.6. Matrix Transpositioning

⍉ (matrix transposition) monad function replaces matrix as inverse indexes.
This function supports only two dimentional array (matrix). But for extending to operator, it can support higher dimentional tensor. Here, I’ll explain only for matrix:

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← ⍉A;
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

8  9 ¯9
9  7 ¯8
4 ¯5  7
3  3  6

3.3. String Manipulations

If you have even a little programming experience, you may have been frustrated that we haven’t covered strings yet. Sorry to keep you waiting.

3.3.1. Defining String

Recent modern programming languages don’t take care

We don’t define string like this:

STR: κ[?] ← "H" "E" "L" "L" "O";
⎕ ← STR;

Unfortunately, this is the result:

STRING DEFINISION ERROR: STRING CANNOT EXTEND HIGH DIMENTIONAL ARRAY WITHOUT USING RESHAPE

But, like this:

STR: κ[?] ← "HELLO";
⎕ ← STR;
HELLO

Or, like this:

STR: κ[?] ← "H" & "E" & "L" & "L" & "O";
⎕ ← STR;
HELLO

Character, and string has few methods than boolean or number.
They are only extracting by indexes, ρ (shape extractor) monad, ρ (reshape) dyad, & (combination) dyad, = (equal) dyad, ≡ (match) dyad, and ⍉ (matrix transposition) dyad.

3.3.2. Embedding Variables

This is completely special operation. We can embed variables even any types, and even high dimentional array in string.

A ← 3 4 ρ 8 9 4 3 9 7 ¯5 3 ¯9 ¯8 7 6;
⎕ ← A;
⎕ ← "";
⎕ ← "MATRIX: {A}";
⎕ ← "";
⎕ ← ρ "MATRIX: {A}";
 8  9  4 3
 9  7 ¯5 3
¯9 ¯8  7 6

MATRIX:  8  9  4 3
         9  7 ¯5 3
        ¯9 ¯8  7 6

3 18

3.4. Empty Value

There is also “empty value”.
The easiest examples to try are ι (ordered index array generator) or ? (shuffled index array generator). Or you can also define it directly.

⎕ ← φ;
⎕ ← ι0;
⎕ ← ?0;
φ
φ
φ

The simplest example is actually empty string, but this requires special handling when outputting to the console.

⎕ ← "";

Because AROAPL compiler check its type even if the value is empty. Incidentally, if you define direct empty value, the type becomes inferred type or boolean.

On top of that, its handling becomes quite special in various ways. For example, in an + (plus) operation, it becomes an empty value.

⎕ ← 10 + φ;
φ

But it doesn’t work:

⎕ ← 10 + "";
VALUE ERROR: ALL ELEMENTS MUST BE THE SAME TYPE

In case of some monad methods, they returns the same empty value:

⎕ ← +φ;
⎕ ← -φ;
⎕ ← ×φ;
⎕ ← ÷φ;
⎕ ← ⌈φ;
⎕ ← ⌊φ;
⎕ ← ¬φ;
⎕ ← =φ;
φ
φ
φ
φ
φ
φ
φ
φ

In case of & (combination) method, returns the same array:

⎕ ← 10 8 3 & φ;
10 8 3

And, it doesn’t work:

⎕ ← ιφ;
INDEX ARRAY GENERATION ERROR: IT MUST BE SCALAR

It doesn’t work, too:

⎕ ← ?φ;
INDEX ARRAY GENERATION ERROR: IT MUST BE SCALAR